import torch
import torch.nn as nn
from torch.autograd import Variable
import torch.nn.functional as F

import matplotlib.pyplot as plt


n_data = torch.ones(100, 2)

x0 = torch.normal(2 * n_data, 1)
y0 = torch.zeros(100)

x1 = torch.normal(- 2 * n_data, 1)
y1 = torch.ones(100)

x = torch.cat((x0, x1), 0).type(torch.FloatTensor)
y = torch.cat((y0, y1)).type(torch.LongTensor)
print(x)
print(y)

x, y = Variable(x), Variable(y)

# plt.scatter(x.data.numpy()[:, 0], x.data.numpy()[:, 1], c=y.data.numpy(), s=100)
# plt.show()


class Net(nn.Module):
    def __init__(self, n_features, n_hidden, n_output):
        super(Net, self).__init__()
        self.hidden = nn.Linear(n_features, n_hidden)
        self.predict = nn.Linear(n_hidden, n_output)

    def forward(self, x):
        x = F.relu(self.hidden(x))
        x = F.log_softmax(self.predict(x))
        return x

# build net with nn.Module
# net = Net(2, 10, 2)

# build net with nn.Sequential
net = nn.Sequential(
    nn.Linear(2, 10),
    nn.ReLU(),
    nn.Linear(10, 2),
    nn.LogSigmoid()
)

print(net)

optimizer = torch.optim.SGD(net.parameters(), lr=0.02)

loss_func = torch.nn.CrossEntropyLoss()  # cross entropy

# plot realtime
plt.ion()
plt.show()

for t in range(100):
    pred = net(x)
    loss = loss_func(pred, y)

    optimizer.zero_grad()
    loss.backward()  # compute backprop of loss

    optimizer.step()

    if t % 2 == 0:
        plt.cla()
        pred = torch.max(pred, 1)[1].data.numpy().squeeze()
        target = y.data.numpy()
        plt.scatter(x.data.numpy()[:, 0], x.data.numpy()[:, 1], c=pred, s=100)
        accuracy = sum(pred == target) / 200
        plt.text(1.5, -4, 'Accuracy=%.2f' % accuracy, fontdict={'size': 20, 'color': 'red'})
        plt.pause(0.1)

plt.ioff()
plt.show()

